From 51359ed8958424d36bcd158904c41d2a7de30aec Mon Sep 17 00:00:00 2001 From: "iap10@freefall.cl.cam.ac.uk" Date: Sat, 21 May 2005 10:29:40 +0000 Subject: [PATCH] bitkeeper revision 1.1502 (428f0d94bUM6nCIYBQRzeFSs29KMDg) Clean up droppings that occured when pulling the upgrade to 2.4.30 from 2.0-testing into unstable. Signed-off-by: ian@xensource.com --- .rootkeys | 6 - .../arch/xen/drivers/usbif/Makefile | 10 - .../arch/xen/drivers/usbif/backend/Makefile | 3 - .../arch/xen/drivers/usbif/frontend/Makefile | 3 - .../arch/xen/kernel/ioport.c | 43 - .../arch/xen/kernel/pci-dma.c | 137 -- linux-2.4.29-xen-sparse/drivers/usb/hcd.c | 1511 ----------------- 7 files changed, 1713 deletions(-) delete mode 100644 linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile delete mode 100644 linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile delete mode 100644 linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile delete mode 100644 linux-2.4.29-xen-sparse/arch/xen/kernel/ioport.c delete mode 100644 linux-2.4.29-xen-sparse/arch/xen/kernel/pci-dma.c delete mode 100644 linux-2.4.29-xen-sparse/drivers/usb/hcd.c diff --git a/.rootkeys b/.rootkeys index 3e97485884..af919b3407 100644 --- a/.rootkeys +++ b/.rootkeys @@ -123,12 +123,6 @@ 423e7e8dVDL1WLfbmQWuXMbetYk4jA freebsd-5.3-xen-sparse/mkbuildtree 423e7e8dBrOrAbydK6h49bY0VvDgPw freebsd-5.3-xen-sparse/xenfbsd_kernel_build 4187ca95_eQN62ugV1zliQcfzXrHnw install.sh -41ee5e8b_2rt-qHzbDXtIoBzOli0EA linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile -41ee5e8bUhF4tH7OoJaVbUxdXqneVw linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile -41ee5e8bSPpxzhGO6TrY20TegW3cZg linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile -4241709bNBs1q4Ss32YW0CyFVOGhEg linux-2.4.29-xen-sparse/arch/xen/kernel/ioport.c -4270e964iKFC24KiVm6jC5Eo7MxV6w linux-2.4.29-xen-sparse/arch/xen/kernel/pci-dma.c -41f97f64nW0wmgLxhwzPTzkF4E5ERA linux-2.4.29-xen-sparse/drivers/usb/hcd.c 3e5a4e6589G-U42lFKs43plskXoFxQ linux-2.4.30-xen-sparse/Makefile 3e5a4e65IEPjnWPZ5w3TxS5scV8Ewg linux-2.4.30-xen-sparse/arch/xen/Makefile 3e5a4e65n-KhsEAs-A4ULiStBp-r6w linux-2.4.30-xen-sparse/arch/xen/boot/Makefile diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile deleted file mode 100644 index 1b3eb41a24..0000000000 --- a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile +++ /dev/null @@ -1,10 +0,0 @@ - -O_TARGET := drv.o - -subdir-$(CONFIG_XEN_USB_FRONTEND) += frontend -obj-$(CONFIG_XEN_USB_FRONTEND) += frontend/drv.o - -subdir-$(CONFIG_XEN_USB_BACKEND) += backend -obj-$(CONFIG_XEN_USB_BACKEND) += backend/drv.o - -include $(TOPDIR)/Rules.make diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile deleted file mode 100644 index b5226dd039..0000000000 --- a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -O_TARGET := drv.o -obj-y := main.o interface.o control.o # vrh.o don't think I need this! -include $(TOPDIR)/Rules.make diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile deleted file mode 100644 index 032d02d7cc..0000000000 --- a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -O_TARGET := drv.o -obj-y := main.o -include $(TOPDIR)/Rules.make diff --git a/linux-2.4.29-xen-sparse/arch/xen/kernel/ioport.c b/linux-2.4.29-xen-sparse/arch/xen/kernel/ioport.c deleted file mode 100644 index 4a716e0164..0000000000 --- a/linux-2.4.29-xen-sparse/arch/xen/kernel/ioport.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -asmlinkage long sys_iopl(unsigned int new_io_pl) -{ - unsigned int old_io_pl = current->thread.io_pl; - physdev_op_t op; - - if (new_io_pl > 3) - return -EINVAL; - - /* Need "raw I/O" privileges for direct port access. */ - if ((new_io_pl > old_io_pl) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* Maintain OS privileges even if user attempts to relinquish them. */ - if (new_io_pl == 0) - new_io_pl = 1; - - /* Change our version of the privilege levels. */ - current->thread.io_pl = new_io_pl; - - /* Force the change at ring 0. */ - op.cmd = PHYSDEVOP_SET_IOPL; - op.u.set_iopl.iopl = new_io_pl; - HYPERVISOR_physdev_op(&op); - - return 0; -} - -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int turn_on) -{ - return turn_on ? sys_iopl(3) : 0; -} diff --git a/linux-2.4.29-xen-sparse/arch/xen/kernel/pci-dma.c b/linux-2.4.29-xen-sparse/arch/xen/kernel/pci-dma.c deleted file mode 100644 index c984bc6173..0000000000 --- a/linux-2.4.29-xen-sparse/arch/xen/kernel/pci-dma.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Dynamic DMA mapping support. - * - * On i386 there is no hardware dynamic DMA address translation, - * so consistent alloc/free are merely page allocation/freeing. - * The rest of the dynamic DMA mapping interface is implemented - * in asm/pci.h. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define pte_offset_kernel pte_offset - -struct dma_coherent_mem { - void *virt_base; - u32 device_base; - int size; - int flags; - unsigned long *bitmap; -}; - -static void -xen_contig_memory(unsigned long vstart, unsigned int order) -{ - /* - * Ensure multi-page extents are contiguous in machine memory. - * This code could be cleaned up some, and the number of - * hypercalls reduced. - */ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long pfn, i, flags; - - scrub_pages(vstart, 1 << order); - - balloon_lock(flags); - - /* 1. Zap current PTEs, giving away the underlying pages. */ - for (i = 0; i < (1<pte_low >> PAGE_SHIFT; - HYPERVISOR_update_va_mapping( - vstart + (i*PAGE_SIZE), __pte_ma(0), 0); - phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] = - INVALID_P2M_ENTRY; - if (HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation, - &pfn, 1, 0) != 1) BUG(); - } - /* 2. Get a new contiguous memory extent. */ - if (HYPERVISOR_dom_mem_op(MEMOP_increase_reservation, - &pfn, 1, order) != 1) BUG(); - /* 3. Map the new extent in place of old pages. */ - for (i = 0; i < (1<>PAGE_SHIFT)+i); - phys_to_machine_mapping[(__pa(vstart)>>PAGE_SHIFT)+i] = - pfn+i; - } - /* Flush updates through and flush the TLB. */ - flush_tlb_all(); - - balloon_unlock(flags); -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) -void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -#else -void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, int gfp) -#endif -{ - void *ret; - unsigned int order = get_order(size); - unsigned long vstart; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) - int gfp = GFP_ATOMIC; - - if (hwdev == NULL || ((u32)hwdev->dma_mask < 0xffffffff)) - gfp |= GFP_DMA; -#else - struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; - - /* ignore region specifiers */ - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM); - - if (mem) { - int page = bitmap_find_free_region(mem->bitmap, mem->size, - order); - if (page >= 0) { - *dma_handle = mem->device_base + (page << PAGE_SHIFT); - ret = mem->virt_base + (page << PAGE_SHIFT); - memset(ret, 0, size); - return ret; - } - if (mem->flags & DMA_MEMORY_EXCLUSIVE) - return NULL; - } - - if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff)) - gfp |= GFP_DMA; -#endif - - vstart = __get_free_pages(gfp, order); - ret = (void *)vstart; - if (ret == NULL) - return ret; - - xen_contig_memory(vstart, order); - - memset(ret, 0, size); - *dma_handle = virt_to_bus(ret); - - return ret; -} - -void pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - free_pages((unsigned long)vaddr, get_order(size)); -} diff --git a/linux-2.4.29-xen-sparse/drivers/usb/hcd.c b/linux-2.4.29-xen-sparse/drivers/usb/hcd.c deleted file mode 100644 index bc184e896d..0000000000 --- a/linux-2.4.29-xen-sparse/drivers/usb/hcd.c +++ /dev/null @@ -1,1511 +0,0 @@ -/* - * Copyright (c) 2001-2002 by David Brownell - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for UTS_SYSNAME */ - - -#ifdef CONFIG_USB_DEBUG - #define DEBUG -#else - #undef DEBUG -#endif - -#include -#include "hcd.h" - -#include -#include -#include -#include - - -/*-------------------------------------------------------------------------*/ - -/* - * USB Host Controller Driver framework - * - * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing - * HCD-specific behaviors/bugs. Think of it as the "upper level" of - * some drivers, where the "lower level" is hardware-specific. - * - * This does error checks, tracks devices and urbs, and delegates to a - * "hc_driver" only for code (and data) that really needs to know about - * hardware differences. That includes root hub registers, i/o queues, - * and so on ... but as little else as possible. - * - * Shared code includes most of the "root hub" code (these are emulated, - * though each HC's hardware works differently) and PCI glue, plus request - * tracking overhead. The HCD code should only block on spinlocks or on - * hardware handshaking; blocking on software events (such as other kernel - * threads releasing resources, or completing actions) is all generic. - * - * Happens the USB 2.0 spec says this would be invisible inside the "USBD", - * and includes mostly a "HCDI" (HCD Interface) along with some APIs used - * only by the hub driver ... and that neither should be seen or used by - * usb client device drivers. - * - * Contributors of ideas or unattributed patches include: David Brownell, - * Roman Weissgaerber, Rory Bolt, ... - * - * HISTORY: - * 2002-sept Merge some 2.5 updates so we can share hardware level HCD - * code between the 2.4.20+ and 2.5 trees. - * 2002-feb merge to 2.4.19 - * 2001-12-12 Initial patch version for Linux 2.5.1 kernel. - */ - -/*-------------------------------------------------------------------------*/ - -/* host controllers we manage */ -static LIST_HEAD (hcd_list); - -/* used when updating list of hcds */ -static DECLARE_MUTEX (hcd_list_lock); - -/* used when updating hcd data */ -static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED; - -static struct usb_operations hcd_operations; - -/*-------------------------------------------------------------------------*/ - -/* - * Sharable chunks of root hub code. - */ - -/*-------------------------------------------------------------------------*/ - -#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff) -#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff) - -/* usb 2.0 root hub device descriptor */ -static const u8 usb2_rh_dev_descriptor [18] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x00, 0x02, /* __u16 bcdUSB; v2.0 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ - - 0x03, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - -/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */ - -/* usb 1.1 root hub device descriptor */ -static const u8 usb11_rh_dev_descriptor [18] = { - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, 0x01, /* __u16 bcdUSB; v1.1 */ - - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - - 0x00, 0x00, /* __u16 idVendor; */ - 0x00, 0x00, /* __u16 idProduct; */ - KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */ - - 0x03, /* __u8 iManufacturer; */ - 0x02, /* __u8 iProduct; */ - 0x01, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - - -/*-------------------------------------------------------------------------*/ - -/* Configuration descriptors for our root hubs */ - -static const u8 fs_rh_config_descriptor [] = { - - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ - 0x01, /* __u8 bNumInterfaces; (1) */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, - 6: Self-powered, - 5 Remote-wakwup, - 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* __u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */ -}; - -static const u8 hs_rh_config_descriptor [] = { - - /* one configuration */ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, 0x00, /* __u16 wTotalLength; */ - 0x01, /* __u8 bNumInterfaces; (1) */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, - 6: Self-powered, - 5 Remote-wakwup, - 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* USB 1.1: - * USB 2.0, single TT organization (mandatory): - * one interface, protocol 0 - * - * USB 2.0, multiple TT organization (optional): - * two interfaces, protocols 1 (like single TT) - * and 2 (multiple TT mode) ... config is - * sometimes settable - * NOT IMPLEMENTED - */ - - /* one interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */ - 0x00, /* __u8 if_iInterface; */ - - /* one endpoint (status change endpoint) */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ - 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ -}; - -/*-------------------------------------------------------------------------*/ - -/* - * helper routine for returning string descriptors in UTF-16LE - * input can actually be ISO-8859-1; ASCII is its 7-bit subset - */ -static int ascii2utf (char *s, u8 *utf, int utfmax) -{ - int retval; - - for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { - *utf++ = *s++; - *utf++ = 0; - } - return retval; -} - -/* - * rh_string - provides manufacturer, product and serial strings for root hub - * @id: the string ID number (1: serial number, 2: product, 3: vendor) - * @pci_desc: PCI device descriptor for the relevant HC - * @type: string describing our driver - * @data: return packet in UTF-16 LE - * @len: length of the return packet - * - * Produces either a manufacturer, product or serial number string for the - * virtual root hub device. - */ -static int rh_string ( - int id, - struct usb_hcd *hcd, - u8 *data, - int len -) { - char buf [100]; - - // language ids - if (id == 0) { - *data++ = 4; *data++ = 3; /* 4 bytes string data */ - *data++ = 0; *data++ = 0; /* some language id */ - return 4; - - // serial number - } else if (id == 1) { - strcpy (buf, hcd->bus->bus_name); - - // product description - } else if (id == 2) { - strcpy (buf, hcd->product_desc); - - // id 3 == vendor description - } else if (id == 3) { - sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE, - hcd->description); - - // unsupported IDs --> "protocol stall" - } else - return 0; - - data [0] = 2 * (strlen (buf) + 1); - data [1] = 3; /* type == string */ - return 2 + ascii2utf (buf, data + 2, len - 2); -} - - -/* Root hub control transfers execute synchronously */ -static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) -{ - struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet; - u16 typeReq, wValue, wIndex, wLength; - const u8 *bufp = 0; - u8 *ubuf = urb->transfer_buffer; - int len = 0; - - typeReq = (cmd->bRequestType << 8) | cmd->bRequest; - wValue = le16_to_cpu (cmd->wValue); - wIndex = le16_to_cpu (cmd->wIndex); - wLength = le16_to_cpu (cmd->wLength); - - if (wLength > urb->transfer_buffer_length) - goto error; - - /* set up for success */ - urb->status = 0; - urb->actual_length = wLength; - switch (typeReq) { - - /* DEVICE REQUESTS */ - - case DeviceRequest | USB_REQ_GET_STATUS: - // DEVICE_REMOTE_WAKEUP - ubuf [0] = 1; // selfpowered - ubuf [1] = 0; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: - case DeviceOutRequest | USB_REQ_SET_FEATURE: - dbg ("no device features yet yet"); - break; - case DeviceRequest | USB_REQ_GET_CONFIGURATION: - ubuf [0] = 1; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - break; - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (wValue & 0xff00) { - case USB_DT_DEVICE << 8: - if (hcd->driver->flags & HCD_USB2) - bufp = usb2_rh_dev_descriptor; - else if (hcd->driver->flags & HCD_USB11) - bufp = usb11_rh_dev_descriptor; - else - goto error; - len = 18; - break; - case USB_DT_CONFIG << 8: - if (hcd->driver->flags & HCD_USB2) { - bufp = hs_rh_config_descriptor; - len = sizeof hs_rh_config_descriptor; - } else { - bufp = fs_rh_config_descriptor; - len = sizeof fs_rh_config_descriptor; - } - break; - case USB_DT_STRING << 8: - urb->actual_length = rh_string ( - wValue & 0xff, hcd, - ubuf, wLength); - break; - default: - goto error; - } - break; - case DeviceRequest | USB_REQ_GET_INTERFACE: - ubuf [0] = 0; - /* FALLTHROUGH */ - case DeviceOutRequest | USB_REQ_SET_INTERFACE: - break; - case DeviceOutRequest | USB_REQ_SET_ADDRESS: - // wValue == urb->dev->devaddr - dbg ("%s root hub device address %d", - hcd->bus->bus_name, wValue); - break; - - /* INTERFACE REQUESTS (no defined feature/status flags) */ - - /* ENDPOINT REQUESTS */ - - case EndpointRequest | USB_REQ_GET_STATUS: - // ENDPOINT_HALT flag - ubuf [0] = 0; - ubuf [1] = 0; - /* FALLTHROUGH */ - case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: - case EndpointOutRequest | USB_REQ_SET_FEATURE: - dbg ("no endpoint features yet"); - break; - - /* CLASS REQUESTS (and errors) */ - - default: - /* non-generic request */ - urb->status = hcd->driver->hub_control (hcd, - typeReq, wValue, wIndex, - ubuf, wLength); - break; -error: - /* "protocol stall" on error */ - urb->status = -EPIPE; - dbg ("unsupported hub control message (maxchild %d)", - urb->dev->maxchild); - } - if (urb->status) { - urb->actual_length = 0; - dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d", - typeReq, wValue, wIndex, wLength, urb->status); - } - if (bufp) { - if (urb->transfer_buffer_length < len) - len = urb->transfer_buffer_length; - urb->actual_length = len; - // always USB_DIR_IN, toward host - memcpy (ubuf, bufp, len); - } - - /* any errors get returned through the urb completion */ - usb_hcd_giveback_urb (hcd, urb, 0); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * Root Hub interrupt transfers are synthesized with a timer. - * Completions are called in_interrupt() but not in_irq(). - */ - -static void rh_report_status (unsigned long ptr); - -static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb) -{ - int len = 1 + (urb->dev->maxchild / 8); - - /* rh_timer protected by hcd_data_lock */ - if (timer_pending (&hcd->rh_timer) - || urb->status != -EINPROGRESS - || !HCD_IS_RUNNING (hcd->state) - || urb->transfer_buffer_length < len) { - dbg ("not queuing status urb, stat %d", urb->status); - return -EINVAL; - } - - urb->hcpriv = hcd; /* nonzero to indicate it's queued */ - init_timer (&hcd->rh_timer); - hcd->rh_timer.function = rh_report_status; - hcd->rh_timer.data = (unsigned long) urb; - /* USB 2.0 spec says 256msec; this is close enough */ - hcd->rh_timer.expires = jiffies + HZ/4; - add_timer (&hcd->rh_timer); - return 0; -} - -/* timer callback */ - -static void rh_report_status (unsigned long ptr) -{ - struct urb *urb; - struct usb_hcd *hcd; - int length; - unsigned long flags; - - urb = (struct urb *) ptr; - spin_lock_irqsave (&urb->lock, flags); - if (!urb->dev) { - spin_unlock_irqrestore (&urb->lock, flags); - return; - } - - hcd = urb->dev->bus->hcpriv; - if (urb->status == -EINPROGRESS) { - if (HCD_IS_RUNNING (hcd->state)) { - length = hcd->driver->hub_status_data (hcd, - urb->transfer_buffer); - spin_unlock_irqrestore (&urb->lock, flags); - if (length > 0) { - urb->actual_length = length; - urb->status = 0; - urb->complete (urb); - } - spin_lock_irqsave (&hcd_data_lock, flags); - urb->status = -EINPROGRESS; - if (HCD_IS_RUNNING (hcd->state) - && rh_status_urb (hcd, urb) != 0) { - /* another driver snuck in? */ - dbg ("%s, can't resubmit roothub status urb?", - hcd->bus->bus_name); - spin_unlock_irqrestore (&hcd_data_lock, flags); - BUG (); - } - spin_unlock_irqrestore (&hcd_data_lock, flags); - } else - spin_unlock_irqrestore (&urb->lock, flags); - } else { - /* this urb's been unlinked */ - urb->hcpriv = 0; - spin_unlock_irqrestore (&urb->lock, flags); - - usb_hcd_giveback_urb (hcd, urb, 0); - } -} - -/*-------------------------------------------------------------------------*/ - -static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb) -{ - if (usb_pipeint (urb->pipe)) { - int retval; - unsigned long flags; - - spin_lock_irqsave (&hcd_data_lock, flags); - retval = rh_status_urb (hcd, urb); - spin_unlock_irqrestore (&hcd_data_lock, flags); - return retval; - } - if (usb_pipecontrol (urb->pipe)) - return rh_call_control (hcd, urb); - else - return -EINVAL; -} - -/*-------------------------------------------------------------------------*/ - -static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb) -{ - unsigned long flags; - - spin_lock_irqsave (&hcd_data_lock, flags); - del_timer_sync (&hcd->rh_timer); - hcd->rh_timer.data = 0; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - /* we rely on RH callback code not unlinking its URB! */ - usb_hcd_giveback_urb (hcd, urb, 0); -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_PCI - -/* PCI-based HCs are normal, but custom bus glue should be ok */ - -static void hcd_irq (int irq, void *__hcd, struct pt_regs *r); -static void hc_died (struct usb_hcd *hcd); - -/*-------------------------------------------------------------------------*/ - -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ - -/** - * usb_hcd_pci_probe - initialize PCI-based HCDs - * @dev: USB Host Controller being probed - * @id: pci hotplug id connecting controller to HCD framework - * Context: !in_interrupt() - * - * Allocates basic PCI resources for this USB host controller, and - * then invokes the start() method for the HCD associated with it - * through the hotplug entry's driver_data. - * - * Store this function in the HCD's struct pci_driver as probe(). - */ -int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id) -{ - struct hc_driver *driver; - unsigned long resource, len; - void *base; - struct usb_bus *bus; - struct usb_hcd *hcd; - int retval, region; - char buf [8], *bufp = buf; - - if (!id || !(driver = (struct hc_driver *) id->driver_data)) - return -EINVAL; - - if (pci_enable_device (dev) < 0) - return -ENODEV; - - if (!dev->irq) { - err ("Found HC with no IRQ. Check BIOS/PCI %s setup!", - dev->slot_name); - return -ENODEV; - } - - if (driver->flags & HCD_MEMORY) { // EHCI, OHCI - region = 0; - resource = pci_resource_start (dev, 0); - len = pci_resource_len (dev, 0); - if (!request_mem_region (resource, len, driver->description)) { - dbg ("controller already in use"); - return -EBUSY; - } - base = ioremap_nocache (resource, len); - if (base == NULL) { - dbg ("error mapping memory"); - retval = -EFAULT; -clean_1: - release_mem_region (resource, len); - err ("init %s fail, %d", dev->slot_name, retval); - return retval; - } - - } else { // UHCI - resource = len = 0; - for (region = 0; region < PCI_ROM_RESOURCE; region++) { - if (!(pci_resource_flags (dev, region) & IORESOURCE_IO)) - continue; - - resource = pci_resource_start (dev, region); - len = pci_resource_len (dev, region); - if (request_region (resource, len, - driver->description)) - break; - } - if (region == PCI_ROM_RESOURCE) { - dbg ("no i/o regions available"); - return -EBUSY; - } - base = (void *) resource; - } - - // driver->start(), later on, will transfer device from - // control by SMM/BIOS to control by Linux (if needed) - - pci_set_master (dev); - hcd = driver->hcd_alloc (); - if (hcd == NULL){ - dbg ("hcd alloc fail"); - retval = -ENOMEM; -clean_2: - if (driver->flags & HCD_MEMORY) { - iounmap (base); - goto clean_1; - } else { - release_region (resource, len); - err ("init %s fail, %d", dev->slot_name, retval); - return retval; - } - } - pci_set_drvdata(dev, hcd); - hcd->driver = driver; - hcd->description = driver->description; - hcd->pdev = dev; - printk (KERN_INFO "%s %s: %s\n", - hcd->description, dev->slot_name, dev->name); - -#ifndef __sparc__ - sprintf (buf, "%d", dev->irq); -#else - bufp = __irq_itoa(dev->irq); -#endif - if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd) - != 0) { - err ("request interrupt %s failed", bufp); - retval = -EBUSY; -clean_3: - driver->hcd_free (hcd); - goto clean_2; - } - hcd->irq = dev->irq; - - hcd->regs = base; - hcd->region = region; - printk (KERN_INFO "%s %s: irq %s, %s %p\n", - hcd->description, dev->slot_name, bufp, - (driver->flags & HCD_MEMORY) ? "pci mem" : "io base", - base); - -// FIXME simpler: make "bus" be that data, not pointer to it. -// (fixed in 2.5) - bus = usb_alloc_bus (&hcd_operations); - if (bus == NULL) { - dbg ("usb_alloc_bus fail"); - retval = -ENOMEM; - free_irq (dev->irq, hcd); - goto clean_3; - } - hcd->bus = bus; - bus->bus_name = dev->slot_name; - hcd->product_desc = dev->name; - bus->hcpriv = (void *) hcd; - - INIT_LIST_HEAD (&hcd->dev_list); - INIT_LIST_HEAD (&hcd->hcd_list); - - down (&hcd_list_lock); - list_add (&hcd->hcd_list, &hcd_list); - up (&hcd_list_lock); - - usb_register_bus (bus); - - if ((retval = driver->start (hcd)) < 0) - usb_hcd_pci_remove (dev); - - return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_probe); - - -/* may be called without controller electrically present */ -/* may be called with controller, bus, and devices active */ - -/** - * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs - * @dev: USB Host Controller being removed - * Context: !in_interrupt() - * - * Reverses the effect of usb_hcd_pci_probe(), first invoking - * the HCD's stop() method. It is always called from a thread - * context, normally "rmmod", "apmd", or something similar. - * - * Store this function in the HCD's struct pci_driver as remove(). - */ -void usb_hcd_pci_remove (struct pci_dev *dev) -{ - struct usb_hcd *hcd; - struct usb_device *hub; - - hcd = pci_get_drvdata(dev); - if (!hcd) - return; - printk (KERN_INFO "%s %s: remove state %x\n", - hcd->description, dev->slot_name, hcd->state); - - if (in_interrupt ()) BUG (); - - hub = hcd->bus->root_hub; - hcd->state = USB_STATE_QUIESCING; - - dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name); - usb_disconnect (&hub); - // usb_disconnect (&hcd->bus->root_hub); - - hcd->driver->stop (hcd); - hcd->state = USB_STATE_HALT; - - free_irq (hcd->irq, hcd); - if (hcd->driver->flags & HCD_MEMORY) { - iounmap (hcd->regs); - release_mem_region (pci_resource_start (dev, 0), - pci_resource_len (dev, 0)); - } else { - release_region (pci_resource_start (dev, hcd->region), - pci_resource_len (dev, hcd->region)); - } - - down (&hcd_list_lock); - list_del (&hcd->hcd_list); - up (&hcd_list_lock); - - usb_deregister_bus (hcd->bus); - usb_free_bus (hcd->bus); - hcd->bus = NULL; - - hcd->driver->hcd_free (hcd); -} -EXPORT_SYMBOL (usb_hcd_pci_remove); - - -#ifdef CONFIG_PM - -/* - * Some "sleep" power levels imply updating struct usb_driver - * to include a callback asking hcds to do their bit by checking - * if all the drivers can suspend. Gets involved with remote wakeup. - * - * If there are pending urbs, then HCs will need to access memory, - * causing extra power drain. New sleep()/wakeup() PM calls might - * be needed, beyond PCI suspend()/resume(). The root hub timer - * still be accessing memory though ... - * - * FIXME: USB should have some power budgeting support working with - * all kinds of hubs. - * - * FIXME: This assumes only D0->D3 suspend and D3->D0 resume. - * D1 and D2 states should do something, yes? - * - * FIXME: Should provide generic enable_wake(), calling pci_enable_wake() - * for all supported states, so that USB remote wakeup can work for any - * devices that support it (and are connected via powered hubs). - * - * FIXME: resume doesn't seem to work right any more... - */ - - -// 2.4 kernels have issued concurrent resumes (w/APM) -// we defend against that error; PCI doesn't yet. - -/** - * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD - * @dev: USB Host Controller being suspended - * - * Store this function in the HCD's struct pci_driver as suspend(). - */ -int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state) -{ - struct usb_hcd *hcd; - int retval; - - hcd = pci_get_drvdata(dev); - printk (KERN_INFO "%s %s: suspend to state %d\n", - hcd->description, dev->slot_name, state); - - pci_save_state (dev, hcd->pci_state); - - // FIXME for all connected devices, leaf-to-root: - // driver->suspend() - // proposed "new 2.5 driver model" will automate that - - /* driver may want to disable DMA etc */ - retval = hcd->driver->suspend (hcd, state); - hcd->state = USB_STATE_SUSPENDED; - - pci_set_power_state (dev, state); - return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_suspend); - -/** - * usb_hcd_pci_resume - power management resume of a PCI-based HCD - * @dev: USB Host Controller being resumed - * - * Store this function in the HCD's struct pci_driver as resume(). - */ -int usb_hcd_pci_resume (struct pci_dev *dev) -{ - struct usb_hcd *hcd; - int retval; - - hcd = pci_get_drvdata(dev); - printk (KERN_INFO "%s %s: resume\n", - hcd->description, dev->slot_name); - - /* guard against multiple resumes (APM bug?) */ - atomic_inc (&hcd->resume_count); - if (atomic_read (&hcd->resume_count) != 1) { - err ("concurrent PCI resumes for %s", hcd->bus->bus_name); - retval = 0; - goto done; - } - - retval = -EBUSY; - if (hcd->state != USB_STATE_SUSPENDED) { - dbg ("can't resume, not suspended!"); - goto done; - } - hcd->state = USB_STATE_RESUMING; - - pci_set_power_state (dev, 0); - pci_restore_state (dev, hcd->pci_state); - - retval = hcd->driver->resume (hcd); - if (!HCD_IS_RUNNING (hcd->state)) { - dbg ("resume %s failure, retval %d", - hcd->bus->bus_name, retval); - hc_died (hcd); -// FIXME: recover, reset etc. - } else { - // FIXME for all connected devices, root-to-leaf: - // driver->resume (); - // proposed "new 2.5 driver model" will automate that - } - -done: - atomic_dec (&hcd->resume_count); - return retval; -} -EXPORT_SYMBOL (usb_hcd_pci_resume); - -#endif /* CONFIG_PM */ - -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * Generic HC operations. - */ - -/*-------------------------------------------------------------------------*/ - -/* called from khubd, or root hub init threads for hcd-private init */ -static int hcd_alloc_dev (struct usb_device *udev) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd; - unsigned long flags; - - if (!udev || udev->hcpriv) - return -EINVAL; - if (!udev->bus || !udev->bus->hcpriv) - return -ENODEV; - hcd = udev->bus->hcpriv; - if (hcd->state == USB_STATE_QUIESCING) - return -ENOLINK; - - dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL); - if (dev == NULL) - return -ENOMEM; - memset (dev, 0, sizeof *dev); - - INIT_LIST_HEAD (&dev->dev_list); - INIT_LIST_HEAD (&dev->urb_list); - - spin_lock_irqsave (&hcd_data_lock, flags); - list_add (&dev->dev_list, &hcd->dev_list); - // refcount is implicit - udev->hcpriv = dev; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static void hcd_panic (void *_hcd) -{ - struct usb_hcd *hcd = _hcd; - hcd->driver->stop (hcd); -} - -static void hc_died (struct usb_hcd *hcd) -{ - struct list_head *devlist, *urblist; - struct hcd_dev *dev; - struct urb *urb; - unsigned long flags; - - /* flag every pending urb as done */ - spin_lock_irqsave (&hcd_data_lock, flags); - list_for_each (devlist, &hcd->dev_list) { - dev = list_entry (devlist, struct hcd_dev, dev_list); - list_for_each (urblist, &dev->urb_list) { - urb = list_entry (urblist, struct urb, urb_list); - dbg ("shutdown %s urb %p pipe %x, current status %d", - hcd->bus->bus_name, - urb, urb->pipe, urb->status); - if (urb->status == -EINPROGRESS) - urb->status = -ESHUTDOWN; - } - } - urb = (struct urb *) hcd->rh_timer.data; - if (urb) - urb->status = -ESHUTDOWN; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - if (urb) - rh_status_dequeue (hcd, urb); - - /* hcd->stop() needs a task context */ - INIT_TQUEUE (&hcd->work, hcd_panic, hcd); - (void) schedule_task (&hcd->work); -} - -/*-------------------------------------------------------------------------*/ - -static void urb_unlink (struct urb *urb) -{ - unsigned long flags; - struct usb_device *dev; - - /* Release any periodic transfer bandwidth */ - if (urb->bandwidth) - usb_release_bandwidth (urb->dev, urb, - usb_pipeisoc (urb->pipe)); - - /* clear all state linking urb to this dev (and hcd) */ - - spin_lock_irqsave (&hcd_data_lock, flags); - list_del_init (&urb->urb_list); - dev = urb->dev; - urb->dev = NULL; - usb_dec_dev_use (dev); - spin_unlock_irqrestore (&hcd_data_lock, flags); -} - - -/* may be called in any context with a valid urb->dev usecount */ -/* caller surrenders "ownership" of urb */ - -static int hcd_submit_urb (struct urb *urb) -{ - int status; - struct usb_hcd *hcd; - struct hcd_dev *dev; - unsigned long flags; - int pipe, temp, max; - int mem_flags; - - if (!urb || urb->hcpriv || !urb->complete) - return -EINVAL; - - urb->status = -EINPROGRESS; - urb->actual_length = 0; - urb->bandwidth = 0; - INIT_LIST_HEAD (&urb->urb_list); - - if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0) - return -ENODEV; - hcd = urb->dev->bus->hcpriv; - dev = urb->dev->hcpriv; - if (!hcd || !dev) - return -ENODEV; - - /* can't submit new urbs when quiescing, halted, ... */ - if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state)) - return -ESHUTDOWN; - pipe = urb->pipe; - temp = usb_pipetype (urb->pipe); - if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe), - usb_pipeout (pipe))) - return -EPIPE; - - /* NOTE: 2.5 passes this value explicitly in submit() */ - mem_flags = GFP_ATOMIC; - - /* FIXME there should be a sharable lock protecting us against - * config/altsetting changes and disconnects, kicking in here. - */ - - /* Sanity check, so HCDs can rely on clean data */ - max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe)); - if (max <= 0) { - err ("bogus endpoint (bad maxpacket)"); - return -EINVAL; - } - - /* "high bandwidth" mode, 1-3 packets/uframe? */ - if (urb->dev->speed == USB_SPEED_HIGH) { - int mult; - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - mult = 1 + ((max >> 11) & 0x03); - max &= 0x03ff; - max *= mult; - } - } - - /* periodic transfers limit size per frame/uframe */ - switch (temp) { - case PIPE_ISOCHRONOUS: { - int n, len; - - if (urb->number_of_packets <= 0) - return -EINVAL; - for (n = 0; n < urb->number_of_packets; n++) { - len = urb->iso_frame_desc [n].length; - if (len < 0 || len > max) - return -EINVAL; - } - - } - break; - case PIPE_INTERRUPT: - if (urb->transfer_buffer_length > max) - return -EINVAL; - } - - /* the I/O buffer must usually be mapped/unmapped */ - if (urb->transfer_buffer_length < 0) - return -EINVAL; - - if (urb->next) { - warn ("use explicit queuing not urb->next"); - return -EINVAL; - } - -#ifdef DEBUG - /* stuff that drivers shouldn't do, but which shouldn't - * cause problems in HCDs if they get it wrong. - */ - { - unsigned int orig_flags = urb->transfer_flags; - unsigned int allowed; - - /* enforce simple/standard policy */ - allowed = USB_ASYNC_UNLINK; // affects later unlinks - allowed |= USB_NO_FSBR; // only affects UHCI - switch (temp) { - case PIPE_CONTROL: - allowed |= USB_DISABLE_SPD; - break; - case PIPE_BULK: - allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK - | USB_ZERO_PACKET | URB_NO_INTERRUPT; - break; - case PIPE_INTERRUPT: - allowed |= USB_DISABLE_SPD; - break; - case PIPE_ISOCHRONOUS: - allowed |= USB_ISO_ASAP; - break; - } - urb->transfer_flags &= allowed; - - /* fail if submitter gave bogus flags */ - if (urb->transfer_flags != orig_flags) { - err ("BOGUS urb flags, %x --> %x", - orig_flags, urb->transfer_flags); - return -EINVAL; - } - } -#endif - /* - * Force periodic transfer intervals to be legal values that are - * a power of two (so HCDs don't need to). - * - * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC - * supports different values... this uses EHCI/UHCI defaults (and - * EHCI can use smaller non-default values). - */ - switch (temp) { - case PIPE_ISOCHRONOUS: - case PIPE_INTERRUPT: - /* too small? */ - if (urb->interval <= 0) - return -EINVAL; - /* too big? */ - switch (urb->dev->speed) { - case USB_SPEED_HIGH: /* units are microframes */ - // NOTE usb handles 2^15 - if (urb->interval > (1024 * 8)) - urb->interval = 1024 * 8; - temp = 1024 * 8; - break; - case USB_SPEED_FULL: /* units are frames/msec */ - case USB_SPEED_LOW: - if (temp == PIPE_INTERRUPT) { - if (urb->interval > 255) - return -EINVAL; - // NOTE ohci only handles up to 32 - temp = 128; - } else { - if (urb->interval > 1024) - urb->interval = 1024; - // NOTE usb and ohci handle up to 2^15 - temp = 1024; - } - break; - default: - return -EINVAL; - } - /* power of two? */ - while (temp > urb->interval) - temp >>= 1; - urb->interval = temp; - } - - - /* - * FIXME: make urb timeouts be generic, keeping the HCD cores - * as simple as possible. - */ - - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb) - // It would catch submission paths for all urbs. - - /* - * Atomically queue the urb, first to our records, then to the HCD. - * Access to urb->status is controlled by urb->lock ... changes on - * i/o completion (normal or fault) or unlinking. - */ - - // FIXME: verify that quiescing hc works right (RH cleans up) - - spin_lock_irqsave (&hcd_data_lock, flags); - if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) { - usb_inc_dev_use (urb->dev); - list_add (&urb->urb_list, &dev->urb_list); - status = 0; - } else { - INIT_LIST_HEAD (&urb->urb_list); - status = -ESHUTDOWN; - } - spin_unlock_irqrestore (&hcd_data_lock, flags); - if (status) - return status; - - // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag - - /* For 2.4, don't map bounce buffer if it's a root hub operation. */ - if (urb->dev == hcd->bus->root_hub) { - status = rh_urb_enqueue (hcd, urb); - } else { -#ifdef CONFIG_PCI - if (usb_pipecontrol (urb->pipe)) - urb->setup_dma = pci_map_single ( - hcd->pdev, - urb->setup_packet, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); - if (urb->transfer_buffer_length != 0) - urb->transfer_dma = pci_map_single ( - hcd->pdev, - urb->transfer_buffer, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); -#endif - status = hcd->driver->urb_enqueue (hcd, urb, mem_flags); - } - return status; -} - -/*-------------------------------------------------------------------------*/ - -/* called in any context */ -static int hcd_get_frame_number (struct usb_device *udev) -{ - struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv; - return hcd->driver->get_frame_number (hcd); -} - -/*-------------------------------------------------------------------------*/ - -struct completion_splice { // modified urb context: - /* did we complete? */ - struct completion done; - - /* original urb data */ - void (*complete)(struct urb *); - void *context; -}; - -static void unlink_complete (struct urb *urb) -{ - struct completion_splice *splice; - - splice = (struct completion_splice *) urb->context; - - /* issue original completion call */ - urb->complete = splice->complete; - urb->context = splice->context; - urb->complete (urb); - - /* then let the synchronous unlink call complete */ - complete (&splice->done); -} - -/* - * called in any context; note ASYNC_UNLINK restrictions - * - * caller guarantees urb won't be recycled till both unlink() - * and the urb's completion function return - */ -static int hcd_unlink_urb (struct urb *urb) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd = 0; - unsigned long flags; - struct completion_splice splice; - int retval; - - if (!urb) - return -EINVAL; - - /* - * we contend for urb->status with the hcd core, - * which changes it while returning the urb. - * - * Caller guaranteed that the urb pointer hasn't been freed, and - * that it was submitted. But as a rule it can't know whether or - * not it's already been unlinked ... so we respect the reversed - * lock sequence needed for the usb_hcd_giveback_urb() code paths - * (urb lock, then hcd_data_lock) in case some other CPU is now - * unlinking it. - */ - spin_lock_irqsave (&urb->lock, flags); - spin_lock (&hcd_data_lock); - if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) { - retval = -EINVAL; - goto done; - } - - if (!urb->dev || !urb->dev->bus) { - retval = -ENODEV; - goto done; - } - - /* giveback clears dev; non-null means it's linked at this level */ - dev = urb->dev->hcpriv; - hcd = urb->dev->bus->hcpriv; - if (!dev || !hcd) { - retval = -ENODEV; - goto done; - } - - /* Any status except -EINPROGRESS means the HCD has already started - * to return this URB to the driver. In that case, there's no - * more work for us to do. - * - * There's much magic because of "automagic resubmit" of interrupt - * transfers, stopped only by explicit unlinking. We won't issue - * an "it's unlinked" callback more than once, but device drivers - * can need to retry (SMP, -EAGAIN) an unlink request as well as - * fake out the "not yet completed" state (set -EINPROGRESS) if - * unlinking from complete(). Automagic eventually vanishes. - * - * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED - */ - if (urb->status != -EINPROGRESS) { - if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT) - retval = -EAGAIN; - else - retval = -EBUSY; - goto done; - } - - /* maybe set up to block on completion notification */ - if ((urb->transfer_flags & USB_TIMEOUT_KILLED)) - urb->status = -ETIMEDOUT; - else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) { - if (in_interrupt ()) { - dbg ("non-async unlink in_interrupt"); - retval = -EWOULDBLOCK; - goto done; - } - /* synchronous unlink: block till we see the completion */ - init_completion (&splice.done); - splice.complete = urb->complete; - splice.context = urb->context; - urb->complete = unlink_complete; - urb->context = &splice; - urb->status = -ENOENT; - } else { - /* asynchronous unlink */ - urb->status = -ECONNRESET; - } - spin_unlock (&hcd_data_lock); - spin_unlock_irqrestore (&urb->lock, flags); - - if (urb == (struct urb *) hcd->rh_timer.data) { - rh_status_dequeue (hcd, urb); - retval = 0; - } else { - retval = hcd->driver->urb_dequeue (hcd, urb); -// FIXME: if retval and we tried to splice, whoa!! -if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval); - } - - /* block till giveback, if needed */ - if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED)) - && HCD_IS_RUNNING (hcd->state) - && !retval) { - wait_for_completion (&splice.done); - } else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) { - return -EINPROGRESS; - } - goto bye; -done: - spin_unlock (&hcd_data_lock); - spin_unlock_irqrestore (&urb->lock, flags); -bye: - if (retval) - dbg ("%s: hcd_unlink_urb fail %d", - hcd ? hcd->bus->bus_name : "(no bus?)", - retval); - return retval; -} - -/*-------------------------------------------------------------------------*/ - -/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */ - -// FIXME: likely best to have explicit per-setting (config+alt) -// setup primitives in the usbcore-to-hcd driver API, so nothing -// is implicit. kernel 2.5 needs a bunch of config cleanup... - -static int hcd_free_dev (struct usb_device *udev) -{ - struct hcd_dev *dev; - struct usb_hcd *hcd; - unsigned long flags; - - if (!udev || !udev->hcpriv) - return -EINVAL; - - if (!udev->bus || !udev->bus->hcpriv) - return -ENODEV; - - // should udev->devnum == -1 ?? - - dev = udev->hcpriv; - hcd = udev->bus->hcpriv; - - /* device driver problem with refcounts? */ - if (!list_empty (&dev->urb_list)) { - dbg ("free busy dev, %s devnum %d (bug!)", - hcd->bus->bus_name, udev->devnum); - return -EINVAL; - } - - hcd->driver->free_config (hcd, udev); - - spin_lock_irqsave (&hcd_data_lock, flags); - list_del (&dev->dev_list); - udev->hcpriv = NULL; - spin_unlock_irqrestore (&hcd_data_lock, flags); - - kfree (dev); - return 0; -} - -static struct usb_operations hcd_operations = { - allocate: hcd_alloc_dev, - get_frame_number: hcd_get_frame_number, - submit_urb: hcd_submit_urb, - unlink_urb: hcd_unlink_urb, - deallocate: hcd_free_dev, -}; - -/*-------------------------------------------------------------------------*/ - -static void hcd_irq (int irq, void *__hcd, struct pt_regs * r) -{ - struct usb_hcd *hcd = __hcd; - int start = hcd->state; - - if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */ - return; - - hcd->driver->irq (hcd, r); - if (hcd->state != start && hcd->state == USB_STATE_HALT) - hc_died (hcd); -} - -/*-------------------------------------------------------------------------*/ - -/** - * usb_hcd_giveback_urb - return URB from HCD to device driver - * @hcd: host controller returning the URB - * @urb: urb being returned to the USB device driver. - * @regs: saved hardware registers (ignored on 2.4 kernels) - * Context: in_interrupt() - * - * This hands the URB from HCD to its USB device driver, using its - * completion function. The HCD has freed all per-urb resources - * (and is done using urb->hcpriv). It also released all HCD locks; - * the device driver won't cause deadlocks if it resubmits this URB, - * and won't confuse things by modifying and resubmitting this one. - * Bandwidth and other resources will be deallocated. - * - * HCDs must not use this for periodic URBs that are still scheduled - * and will be reissued. They should just call their completion handlers - * until the urb is returned to the device driver by unlinking. - * - * NOTE that no urb->next processing is done, even for isochronous URBs. - * ISO streaming functionality can be achieved by having completion handlers - * re-queue URBs. Such explicit queuing doesn't discard error reports. - */ -void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs) -{ - int is_root_hub_operation; - - /* Work this out here as urb_unlink clears urb->dev */ - is_root_hub_operation = (urb->dev == hcd->bus->root_hub); - - urb_unlink (urb); - - // NOTE: a generic device/urb monitoring hook would go here. - // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev) - // It would catch exit/unlink paths for all urbs, but non-exit - // completions for periodic urbs need hooks inside the HCD. - // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev) - - // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag - -#ifdef CONFIG_PCI - /* For 2.4, don't unmap bounce buffer if it's a root hub operation. */ - if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation) - pci_unmap_single (hcd->pdev, urb->setup_dma, - sizeof (struct usb_ctrlrequest), - PCI_DMA_TODEVICE); - - if ((urb->transfer_buffer_length != 0) && !is_root_hub_operation) - pci_unmap_single (hcd->pdev, urb->transfer_dma, - urb->transfer_buffer_length, - usb_pipein (urb->pipe) - ? PCI_DMA_FROMDEVICE - : PCI_DMA_TODEVICE); -#endif - - /* pass ownership to the completion handler */ - urb->complete (urb); -} -EXPORT_SYMBOL (usb_hcd_giveback_urb); -- 2.30.2